package ldh.im.fxbase.dao;

import ldh.im.fxbase.data.pojo.*;
import ldh.im.fxbase.data.pojo.ext.ImMessageSendExt;
import ldh.im.fxbase.data.pojo.status.ImMessageActionStatus;
import ldh.im.fxbase.data.pojo.status.ImMessageStatus;
import ldh.im.fxbase.util.DbUtil;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ColumnListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.SQLException;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class ImMessageSendDao extends BaseDao {

    private static final Logger LOGGER = LoggerFactory.getLogger(ImMessageSendDao.class);

    private static final String MESSAGE_COLUMNS = "id, messageId, userId, status statusValue, fileStatus fileStatusValue, actionStatus actionStatusValue, createTime, updateTime";

    public void insertMessageSends(List<ImMessageSend> messageSends) throws SQLException {
        if (messageSends.size() < 1) return;
        DbUtil.transaction((queryRunner, connection) -> {
            ColumnListHandler<Long> h = new ColumnListHandler();
            Object[][] paras =
                    messageSends.stream().map(ms-> new Object[] {ms.getMessageId(), ms.getUserId(), valueEnum(ms.getStatus()), valueEnum(ms.getFileStatus()),
                            valueEnum(ms.getActionStatus()),  ms.getCreateTime(), ms.getUpdateTime()}).toArray(Object[][]::new);
            String sql = String.format("insert into im_message_send(messageId, userId, status, fileStatus, actionStatus, createTime, updateTime) " +
                    "values(?, ?, ?, ?, ?, ?, ?)");
            List<Long> ids = queryRunner.insertBatch(connection, sql, h, paras);
            int i = 0;
            for(Long id : ids) {
                messageSends.get(i++).setId(id);
            }
            return ids;
        });
    }

    public ImMessageSend getByMessageIdAndToUserId(Long messageId, String userId) throws SQLException {
        return DbUtil.transaction((queryRunner, connection) -> {
            String sql = String.format("select %s from im_message_send where messageId = ? and userId = ?", MESSAGE_COLUMNS);
            ImMessageSend messageSend = queryRunner.query(connection, sql, new BeanHandler<>(ImMessageSendExt.class), messageId, userId);
            return messageSend;
        });
    }

    public List<ImMessageSend> getByMessageId(Long messageId) throws SQLException {
        return DbUtil.transaction((queryRunner, connection) -> {
            String sql = String.format("select %s from im_message_send where messageId = ?", MESSAGE_COLUMNS);
            List<ImMessageSendExt> messageSends = queryRunner.query(connection, sql, new BeanListHandler<ImMessageSendExt>(ImMessageSendExt.class), messageId);
            return messageSends.stream().map(ms->ms).collect(Collectors.toList());
        });
    }

    public void batchInsertMessageSends(List<ImMessage> imMessages) throws SQLException {
        List<ImMessage> messageList = imMessages.stream().filter(m-> {
            if(m.getMessageSendSet() != null) {
                m.getMessageSendSet().forEach(ms->ms.setMessageId(m.getId()));
                return true;
            }
            return false;
        }).collect(Collectors.toList());
        if (messageList.size() < 1) return;

        DbUtil.transaction((queryRunner, connection) -> {
            ResultSetHandler<Long> h = new ScalarHandler();
            Object[][] paras = messageList.stream().flatMap(m->m.getMessageSendSet().stream())
                    .map(ms-> new Object[] {ms.getMessageId(), ms.getUserId(), valueEnum(ms.getStatus()), valueEnum(ms.getFileStatus()), valueEnum(ms.getActionStatus()), new Date(), new Date()}).toArray(Object[][]::new);
            String sql = String.format("insert into im_message_send(messageId, userId, status, fileStatus, actionStatus, createTime, updateTime) " +
                    "values(?, ?, ?, ?, ?, ?, ?)");
            int[] ids = queryRunner.batch(connection, sql, paras);
            return ids;
        });
    }

    public void batchDeleteMessageSends(List<ImMessage> imMessages) throws SQLException {
        if (imMessages.size() < 1) return;
        DbUtil.transaction((queryRunner, connection) -> {
            ResultSetHandler<Long> h = new ScalarHandler();
            Object[][] paras = imMessages.stream().map(m-> new Object[] {m.getId()}).toArray(Object[][]::new);
            String sql = String.format("delete im_message_send where messageId = ?");
            int[] ids = queryRunner.batch(connection, sql, paras);
            return ids;
        });
    }

    public void cleanMessageSends(List<Long> messageIds) throws SQLException {
        if (messageIds.size() < 1) return;
        DbUtil.transaction((queryRunner, connection) -> {
            ResultSetHandler<Long> h = new ScalarHandler();
            Object[][] paras = messageIds.stream().map(m-> new Object[] {ImMessageStatus.delete.getValue(), m}).toArray(Object[][]::new);
            String sql = String.format("update im_message_send set status = ? where messageId = ?");
            int[] ids = queryRunner.batch(connection, sql, paras);
            return ids;
        });
    }

    public void batchUpdates(List<ImMessageSend> imMessageSends) throws SQLException {
        if (imMessageSends.size() < 1) return;
        DbUtil.transaction((queryRunner, connection) -> {
            ResultSetHandler<Long> h = new ScalarHandler();
            Object[][] paras = imMessageSends.stream().map(ms-> new Object[] {ms.getUpdateTime(), valueEnum(ms.getActionStatus()), ms.getId()}).toArray(Object[][]::new);
            String sql = String.format("update im_message_send set updateTime = ?, actionStatus = ? where id = ?");
            int[] ids = queryRunner.batch(connection, sql, paras);
            if (ids.length != imMessageSends.size()) {
                throw new RuntimeException("更新im_message_send失败");
            }
            return ids;
        });
    }

    /**
     * 更新消息事件状态
     * @param messageId
     * @param actionStatus
     */
    public void changeMessageSendActionStatus(Long messageId, String userId, ImMessageActionStatus actionStatus) throws SQLException {
        DbUtil.transaction((queryRunner, connection) -> {
            String sql = String.format("update im_message_send set actionStatus = ?, updateTime=? where messageId = ? and userId= ?");
            updateBeanById(queryRunner, connection, sql, valueEnum(actionStatus), new Date(), messageId, userId);
            return null;
        });
    }

    public void batchChangeMessageSendActionStatus(String userId, List<ImMessageSend> messageSends) throws SQLException {
        if (messageSends.size() < 1) return;
        Object[][] paras = messageSends.stream().map(ms->new Object[] {valueEnum(ms.getActionStatus()), ms.getUpdateTime(), ms.getMessageId(), userId}).toArray(Object[][]::new);
        DbUtil.transaction((queryRunner, connection) -> {
            String sql = String.format("update im_message_send set actionStatus = ?, updateTime=? where messageId = ? and userId= ?");
            int[] ns = queryRunner.batch(connection, sql, paras);
            return null;
        });
    }

    /**
     * 更新消息事件状态
     * @param imMessageActionDataList
     */
    public void changeMessageSendActionStatus(List<ImMessageActionData> imMessageActionDataList) throws SQLException {
        DbUtil.transaction((queryRunner, connection) -> {
            Object[][] paras = imMessageActionDataList.stream().map(mv-> messageActionVoToUpdateArray(mv)).toArray(Object[][]::new);
            String sql = String.format("update im_message_send set actionStatus = ?, updateTime = ? where messageId = ? and userId= ?");
            LOGGER.info("changeMessageActionStatus SQL {}", sql);
            int[] ns = queryRunner.batch(connection, sql, paras);
            if (ns.length != imMessageActionDataList.size()) {
                throw new RuntimeException("更新im_message失败， n =" + ns.length);
            }
            return null;
        });
    }

    public boolean isSynEnd(Long messageId) throws SQLException {
        return DbUtil.transaction((queryRunner, connection) -> {
            String sql = String.format("select count(*) from im_message_send where messageId = ? ");
            Long size = queryRunner.query(sql, new ScalarHandler<Long>(), messageId);

            String sql2 = String.format("select count(*) from im_message_send where actionStatus in ('2', '7') and messageId = ? ");
            long size2 = queryRunner.query(sql2, new ScalarHandler<Long>(), messageId);
            return size.equals(size2);
        });
    }

    private Object[] messageActionVoToUpdateArray(ImMessageActionData mv) {
        Object[] objArray = new Object[4];
        int i = 0;
        objArray[i++] = valueEnum(mv.getActionStatus());
        objArray[i++] = LocalDateTime.now();
        objArray[i++] = mv.getMessageId();
        objArray[i++] = mv.getUserId();
        return objArray;
    }
}
